/*
 * Copyright (c) 2024. hallele, Inc All rights reserved.
 */

package cn.hallele.infrastructure.util;

import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.stp.StpUtil;
import cn.hallele.infrastructure.util.bean.LoginUser;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.dromara.hutool.http.meta.HeaderName;
import org.dromara.hutool.http.server.servlet.ServletUtil;
import org.dromara.hutool.http.useragent.UserAgent;
import org.dromara.hutool.http.useragent.UserAgentUtil;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;

/**
 * Servlet工具,非web环境无法使用该
 *
 * @author anle5
 * @since 2024/9/11 22:54
 */
@Slf4j
public class NetUtil {
    public static final String LOGIN_USER = "LOGIN_USER";

    /**
     * 请求头里的Request-Id
     */
    public static final String REQUEST_ID = "Request-Id";

    public static final String IP = "IP";
    public static final String OS_NAME = "OS_NAME";
    public static final String OS_VERSION = "OS_VERSION";
    public static final String BROWSER_NAME = "BROWSER_NAME";
    public static final String BROWSER_VERSION = "BROWSER_VERSION";
    public static final String ENGINE_NAME = "ENGINE_NAME";
    public static final String ENGINE_VERSION = "ENGINE_VERSION";

    /**
     * 客户端ID
     */
    private static final String CLIENT_ID = "Client_id";

    /**
     * 获取请求id
     */
    public static String getRequestId() {
        return getHttpServletRequest().getHeader(REQUEST_ID);
    }

    /**
     * 获取客户端ip
     *
     * @return 客户端ip
     */
    public static String getClientIp() {
        return ServletUtil.getClientIP(getHttpServletRequest());
    }

    /**
     * 获取服务端host信息
     *
     * @return 客户端ip
     */
    public static InetAddress getLocalHost() {
        try {
            return InetAddress.getLocalHost();
        } catch (UnknownHostException e) {
            log.error("Can not get localHost", e);
            return null;
        }
    }

    /**
     * 获取客户端id
     *
     * @return 客户端ip
     */
    public static String getClientID() {
        return getHttpServletRequest().getHeader(CLIENT_ID);
    }

    /**
     * 获取服务端id todo
     *
     * @return 客户端ip
     */
    public static String getServerID() {
        return getHttpServletRequest().getHeader(CLIENT_ID);
    }

    /**
     * 获取客户端设备信息
     *
     * @return platformName + version
     */
    public static String getClientStringInfo() {
        UserAgent clientUserAgent = getClientUserAgent();

        String osName = clientUserAgent.getOs().getName();
        String osVersion = clientUserAgent.getOsVersion();
        String browserName = clientUserAgent.getBrowser().getName();
        String browserVersion = clientUserAgent.getVersion();
        String engineName = clientUserAgent.getEngine().getName();
        String engineVersion = clientUserAgent.getEngineVersion();

        return osName + " " + osVersion
                + "|" + browserName + " " + browserVersion
                + "|" + engineName + " " + engineVersion;
    }

    /**
     * 获取客户端设备信息
     *
     * @return 客户端集合
     */
    public static Map<String, String> getClientInfo() {
        UserAgent clientUserAgent = getClientUserAgent();
        HashMap<String, String> clientInfo = new HashMap<>();
        clientInfo.put(IP, getClientIp());
        clientInfo.put(OS_NAME, clientUserAgent.getOs().getName());
        clientInfo.put(OS_VERSION, clientUserAgent.getOsVersion());
        clientInfo.put(BROWSER_NAME, clientUserAgent.getBrowser().getName());
        clientInfo.put(BROWSER_VERSION, clientUserAgent.getVersion());
        clientInfo.put(ENGINE_NAME, clientUserAgent.getEngine().getName());
        clientInfo.put(ENGINE_VERSION, clientUserAgent.getEngineVersion());
        return clientInfo;
    }

    /**
     * 获取客户端设备信息
     *
     * @return 客户端集合
     */
    public static Map<String, String> getServerInfo() {
        OperatingSystemMXBean os = ManagementFactory.getOperatingSystemMXBean();
        HashMap<String, String> serverInfo = new HashMap<>();
        serverInfo.put(OS_NAME, os.getName());
        serverInfo.put(OS_VERSION, os.getVersion());
        return serverInfo;
    }

    /**
     * 获取客户端UserAgent
     *
     * @return UserAgent
     */
    public static UserAgent getClientUserAgent() {
        return UserAgentUtil.parse(getHttpServletRequest().getHeader(HeaderName.USER_AGENT.toString()));
    }

    /**
     * 获取 ServletRequestAttributes
     *
     * @return {@link ServletRequestAttributes}
     */
    public static ServletRequestAttributes getServletRequestAttributes() {
        return (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
    }

    /**
     * 获取 HttpServletRequest
     *
     * @return {@link HttpServletRequest}
     */
    public static HttpServletRequest getHttpServletRequest() {
        return getServletRequestAttributes().getRequest();
    }

    /**
     * 获取当前登录用户
     *
     * @return 当前登录用户
     */
    public static LoginUser getLoginUser() {
        Object object;
        try {
            object = StpUtil.getTokenSession().get(LOGIN_USER);
        } catch (NotLoginException e) {
            // 兼容所有场景
            log.info("Don't have login user.Will return null");
            return null;
        }

        if (object == null) {
            return null;
        }

        if (object instanceof LoginUser loginUser) {
            return loginUser;
        }

        log.error("LoginUser class type not match.It should be {}, but actually is {}", LoginUser.class, object.getClass());
        throw new ClassCastException("LoginUser class type not match.It should be " + LoginUser.class);
    }

    /**
     * 获取当前登录用户
     *
     * @return 当前登录用户
     */
    public static Long getLoginUserId() {
        LoginUser loginUser = getLoginUser();
        if (loginUser != null && loginUser.getId() != null) {
            return loginUser.getId();
        }
        return Long.getLong(getHttpServletRequest().getHeader("INITIATOR_ID"));
    }
}
